<script setup lang="ts">
import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'
import { init as initEChart, type ECharts, type SeriesOption, type EChartsOption } from 'echarts'
import {
  LengthUnit,
  lengthUnitName,
  LengthUnitSelect,
  SpeedUnit,
  speedUnitName,
  SpeedUnitSelect,
  fromMeterConverter,
  notify,
  kt2Mps,
  fromMpsConvert
} from '@/widgets'
import { ISA, AtmosphereModel, AirData } from './core'

const deltaP = ref('0')
const deltaT = ref('0')
const altUnit = ref<LengthUnit>(LengthUnit.M)
const spdUnit = shallowRef<SpeedUnit>(SpeedUnit.KT)

let aModel: AtmosphereModel = ISA
function updateAModel(): boolean {
  const dp = parseFloat(deltaP.value)
  const dt = parseFloat(deltaT.value)
  if (isNaN(dp) || isNaN(dt)) {
    notify.error({
      title: '大气模型数值错误',
      content: '请输入正确的大气模型数值'
    })
    return false
  }
  if (dp === aModel.deltaP && dt === aModel.deltaT) {
    return false
  }
  aModel = new AtmosphereModel(dt, dp)
  return true
}

let airDataList: AirData[] = []
function updateAirDataList() {
  const size = 50
  const at = new Array<AirData>(size)
  for (let i = 0; i < size; i++) {
    at[i] = aModel.getAirData(i * 300)
  }
  airDataList = at
}

type TASItem = {
  altitude: number
  TAS: number
}

type MachLine = {
  mach: number
  list: TASItem[]
}

type CASLine = {
  cas: number
  list: TASItem[]
}

let casTable: CASLine[] = []

function updateCASTable(): void {
  const t = [] as CASLine[]
  let c = 20.0
  while (c < 400.0) {
    t.push(calcCASLine(c))
    c += 20.0
  }
  casTable = t
}

function calcCASLine(kCas: number): CASLine {
  const cas = kt2Mps(kCas)
  const list = airDataList.map((ad) => {
    return {
      altitude: ad.altitude,
      TAS: ad.CAS2TAS(cas)
    }
  })
  return { cas: kCas, list }
}

let machTable: MachLine[] = []

function updateMachTable() {
  const t = [] as MachLine[]
  let m = 0.1
  while (m < 1.0) {
    t.push(calcMachLine(m))
    m += 0.1
  }
  machTable = t
}

function calcMachLine(mach: number): MachLine {
  return {
    mach,
    list: airDataList.map((ad) => {
      return {
        altitude: ad.altitude,
        TAS: ad.mach2TAS(mach)
      }
    })
  }
}

const chartEl = ref<HTMLDivElement>()
let chart: ECharts | null = null

function updateChart() {
  if (!chart) {
    return
  }
  chart.setOption(makeEChartOption())
}

function makeEChartOption(): EChartsOption {
  const series: SeriesOption[] = []
  for (const l of casTable) {
    const name = `${Math.floor(l.cas)}kt`
    series.push(toCASSeries(name, l.list))
  }
  for (const l of machTable) {
    const name = `M${Math.round(l.mach * 100)}`
    series.push(toMachSeries(name, l.list))
  }
  const altUnitName = lengthUnitName(altUnit.value)
  const spdUnitName = speedUnitName(spdUnit.value)
  return {
    title: {
      text: 'CAS/TAS/Mach转换',
      left: 'right',
      subtext: `ΔP[hPa]:${deltaP.value}\nΔT[k]:${deltaT.value}\nCAS:红色\nMach:蓝色\nTAS[${spdUnitName}]:横轴\n高度[${altUnitName}]:纵轴`
    },
    backgroundColor: '#fff',
    tooltip: {
      axisPointer: { type: 'cross' }
    },
    xAxis: {
      name: `TAS(${spdUnitName})`,
      type: 'value',
      interval: 50.0
    },
    yAxis: {
      name: `高度(${altUnitName})`,
      type: 'value',
      interval: altUnit.value === LengthUnit.FT ? 2000.0 : 1000.0
    },
    series
  }
}

const casColor = '#e84545'
function toCASSeries(name: string, line: TASItem[]): SeriesOption {
  const color = casColor
  const opts = toSeries(name, line, color)
  opts.markPoint = {
    data: [
      {
        type: 'max',
        name: name,
        color: color,
        label: { formatter: '{b}' },
        itemStyle: { color }
      }
    ]
  }
  return opts
}

const machColor = '#07689f'
function toMachSeries(name: string, line: TASItem[]): SeriesOption {
  const color = machColor
  const opts = toSeries(name, line, color)
  opts.markPoint = {
    data: [
      {
        type: 'median',
        name: name,
        label: {
          formatter: '{b}'
        },
        itemStyle: { color }
      }
    ]
  }

  return opts
}

function toSeries(name: string, line: TASItem[], color?: string): SeriesOption {
  const spdFn = fromMpsConvert(spdUnit.value)
  const altFn = fromMeterConverter(altUnit.value)
  const spdFn1 = (n: number) => Math.floor(spdFn(n))
  const altFn1 = (n: number) => Math.floor(altFn(n))
  return {
    type: 'line',
    name,
    showSymbol: false,
    lineStyle: {
      color,
      width: 1
    },
    data: line.map((e) => [spdFn1(e.TAS), altFn1(e.altitude)])
  }
}

function updateAll() {
  if (!updateAModel()) {
    return
  }
  updateAirDataList()
  updateCASTable()
  updateMachTable()
  updateChart()
}

onMounted(() => {
  chart = initEChart(chartEl.value)
  updateAirDataList()
  updateCASTable()
  updateMachTable()
  updateChart()
})

onUnmounted(() => {
  chart?.dispose()
})
watch(altUnit, () => updateChart())
watch(spdUnit, () => updateChart())
</script>
<template>
  <div class="air-spd-chart pane-block">
    <div class="row">
      <div class="txt-box col-4em">ΔP[hPa]</div>
      <input type="number" class="input col-6em" v-model="deltaP" />
      <div class="txt-box col-3em" style="margin-left: 2em">ΔT[K]</div>
      <input type="number" class="input col-6em" v-model="deltaT" />
      <button class="button is-primary" style="margin-left: 1em" @click="updateAll">计算</button>
      <div style="margin-left: 1.5em; width: 1.5em" class="border-left" />
      <div class="col-5em txt-box">高度单位</div>
      <LengthUnitSelect v-model="altUnit" :options="[LengthUnit.M, LengthUnit.FT]" />
      <div class="col-5em txt-box" style="margin-left: 2em">速度单位</div>
      <SpeedUnitSelect v-model="spdUnit" :options="[SpeedUnit.MPS, SpeedUnit.KMPH, SpeedUnit.KT]" />
    </div>
    <hr class="border-bottom" style="margin: 0.5em 0" />
    <div class="spd-chart" ref="chartEl"></div>
  </div>
</template>
<style>
.air-spd-chart {
  /* width: 80em; */
  .spd-chart {
    width: 90em;
    height: 55em;
  }
}
</style>
